package com.quanyue.haircut.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.quanyue.auto.cache.core.CacheService;
import com.quanyue.auto.util.KeyGenerator;
import com.quanyue.auto.web.Principal;
import com.quanyue.auto.web.RequestContext;
import com.quanyue.auto.wechat.WechatAware;
import com.quanyue.auto.wechat.handler.WechatContext;
import com.quanyue.haircut.domain.constant.CacheConstants;
import com.quanyue.haircut.domain.entity.User;
import com.quanyue.haircut.user.service.UserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
public class WechatAwareImpl implements WechatAware {

    private static final String ACCESS_KEY = "WX_ACCESS_KEY";
    private final UserService userService;
    private final CacheService cacheService;

    @Autowired
    public WechatAwareImpl(UserService userService, CacheService cacheService) {
        this.userService = userService;
        this.cacheService = cacheService;
    }

    @Override
    public void onLogin(String state, WxMpUser wxUser, RequestContext context) {
        User user = this.createOrUpdate(wxUser);
        context.updatePricipal(new Principal(user.getId(), user.getMerchantNo(), "USER", "WECHAT_MP"));
    }

    @Override
    public void onSubscribe(Integer merchantNo, WxMpUser user) {
        this.createOrUpdate(user);
    }

    @Override
    public String authState(HttpServletRequest httpServletRequest, Integer merchantNo) {
        WechatStateValue stateValue = new WechatStateValue();
        stateValue.setMerchantNo(merchantNo);
        stateValue.setParameters(httpServletRequest.getParameterMap()
                .entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
        String key = KeyGenerator.uuid();
        Map<String, WechatStateValue> map = new ConcurrentHashMap <>();
        map.put(key, stateValue);
        cacheService.set(CacheConstants.STATE_CACHE.name(), map);
        return key;
    }

    @Override
    public Integer merchantNo(String state) {
        Type type = new TypeReference <Map<String, WechatStateValue>>() {
        }.getType();
        Map<String, WechatStateValue> map = cacheService.get(CacheConstants.STATE_CACHE.name(), type);
        WechatStateValue stateValue = map.get(state);
        if (stateValue != null) {
            return stateValue.getMerchantNo();
        }
        return null;
    }

    @Override
    public String redicrectUrl(HttpServletRequest request) {
        String url = request.getServletPath().substring("/wechat/portal/auth".length());
        return url;
    }

    private User createOrUpdate(WxMpUser wxUser) {
        User user = userService.findByOpenId(wxUser.getOpenId());
        if (user == null) {
            user = this.createFrom(wxUser);
            userService.add(user);
        } else if (isChanged(wxUser, user)) {
            userService.update(user);
        }
        return user;
    }

    private User createFrom(WxMpUser wxUser) {
        User user = new User();
        user.setNickName(wxUser.getNickname());
        user.setOpenId(wxUser.getOpenId());
        user.setSex(wxUser.getSexId());
        user.setPhone(BigInteger.ZERO.toString());
        user.setHeadImage(wxUser.getHeadImgUrl());
        user.setDelFlag(false);
        user.setCreateTime(LocalDateTime.now());
        user.setModifyTime(LocalDateTime.now());
        user.setIsManage(false);
        user.setMerchantNo(WechatContext.getMerchantNo());
        return user;
    }

    private boolean isChanged(WxMpUser wxMpUser, User user) {
        boolean changed = false;
        if (!user.getNickName().equals(wxMpUser.getNickname())) {
            user.setNickName(wxMpUser.getNickname());
            changed = true;
        }
        if (!user.getHeadImage().equals(wxMpUser.getHeadImgUrl())) {
            user.setHeadImage(wxMpUser.getHeadImgUrl());
            changed = true;
        }
        return changed;
    }

}
